package cc.fine.svc.main.service.impl;

import cc.fine.svc.common.exception.FineException;
import cc.fine.svc.common.utils.JwtUtils;
import cc.fine.svc.common.utils.R;
import cc.fine.svc.config.redis.utils.RedisCache;
import cc.fine.svc.main.bean.es.UserSearchEsEntity;
import cc.fine.svc.main.bean.po.TblUser;
import cc.fine.svc.main.bean.po.TblUserCount;
import cc.fine.svc.main.bean.vo.UserVo;
import cc.fine.svc.main.service.AccountService;
import cc.fine.svc.main.service.tbl.TblUserCountService;
import cc.fine.svc.main.service.tbl.TblUserService;
import cc.fine.svc.main.utils.EsUtil;
import cc.fine.svc.main.utils.SecurityUtils;
import cc.fine.svc.security.bean.LoginUser;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @AUTHOR: wyihe
 * @DATE: 2023/10/25
 */
@Service
@Transactional
public class AccountServiceImpl implements AccountService {

    @Autowired
    private TblUserService userService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private SecurityUtils securityUtils;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private TblUserCountService userCountService;

    @Autowired
    private EsUtil esUtil;


    @Override
    public R registerForPassword(UserVo vo) {
        // 校验手机号不能重复
        QueryWrapper<TblUser> w = new QueryWrapper<>();
        w.eq("phone", vo.getPhone());
        if (!userService.list(w).isEmpty()) {
            return R.error().message("手机号被注册过了");
        }

        TblUser user = new TblUser();
        BeanUtils.copyProperties(vo, user);

        String userId = UUID.randomUUID().toString();
        user.setFineId(newFineId());
        user.setPassword(securityUtils.getSecret(user.getPassword()));
        user.setId(userId);
        userService.save(user);

        // 数据存入 userCount
        TblUserCount userCount = new TblUserCount();
        userCount.setId(userId);
        userCountService.save(userCount);

        // 数据写入 es
        UserSearchEsEntity entity = new UserSearchEsEntity();
        BeanUtils.copyProperties(user, entity);
        try {
            esUtil.addData(JSON.toJSONString(entity), TblUserService.User_Search_Es_Index, userId);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }




        return R.ok().message("注册成功").data("user", user);
    }

    @Override
    public String newFineId() {

        Integer fineId = redisCache.getCacheObject(FINE_ID_CACHE);

        // 如果 redis 中没有这个数据，就走sql获取
        if (fineId == null) {
            List<TblUser> userList = userService.list();

            // 从零开始
            if (userList.isEmpty())
                fineId = 0;
            else { // 从数据库里查
                fineId = userList.stream()
                        .map(x -> Integer.parseInt(x.getFineId()))
                        .max(Integer::compare).get();
            }
        }

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 7 - String.valueOf(fineId).length(); ++i) {
            sb.append("0");
        }
        sb.append(fineId);

        redisCache.setCacheObject(AccountService.FINE_ID_CACHE, fineId + 1);

        return sb.toString();

    }

    @Override
    public R login(String phone, String password) {
        TblUser user = new TblUser();
        user.setPhone(phone);
        user.setPassword(password);

        // 封装认证对象
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getPhone(), user.getPassword());
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);
        if (authenticate == null) {
            throw new FineException(R.ERROR, "认证失败");
        }

        // 获取用户信息-获取token-完整用户信息存入redis
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        String userId = loginUser.getUser().getId();

        String jwt = JwtUtils.getJwtToken(userId, phone);
        redisCache.setCacheObject("login:"+userId, loginUser, 100, TimeUnit.HOURS);

        return R.ok().data("token", jwt).data("uid", userId);
    }
}
